package utils

import (
	"fmt"
	"regexp"
	"strings"
)

// AuthValidator provides validation functionality for authentication-related data
type AuthValidator struct{}

// NewAuthValidator creates a new AuthValidator instance
func NewAuthValidator() *AuthValidator {
	return &AuthValidator{}
}

// ValidateAuthState validates an AuthState structure
func (av *AuthValidator) ValidateAuthState(state *AuthState) error {
	if state == nil {
		return NewAuthError(ErrTypeConfigInvalid, "auth state cannot be nil", "")
	}
	
	return state.Validate()
}

// ValidateAuthConfig validates an AuthConfig structure
func (av *AuthValidator) ValidateAuthConfig(config *AuthConfig) error {
	if config == nil {
		return NewAuthError(ErrTypeConfigInvalid, "auth config cannot be nil", "")
	}
	
	return config.Validate()
}

// ValidateTokenFormat validates a token against its specified format
func (av *AuthValidator) ValidateTokenFormat(token, format string) error {
	if token == "" {
		return NewAuthError(ErrTypeTokenInvalid, "token cannot be empty", "")
	}
	
	if format == "" {
		return NewAuthError(ErrTypeTokenInvalid, "token format cannot be empty", "")
	}
	
	switch format {
	case "bearer":
		return av.validateBearerToken(token)
	case "api_key":
		return av.validateAPIKeyToken(token)
	case "custom":
		return av.validateCustomToken(token)
	default:
		return NewAuthError(ErrTypeTokenInvalid,
			fmt.Sprintf("unsupported token format: %s", format),
			"supported formats: bearer, api_key, custom")
	}
}

// ValidateJSONPath validates a JSON path expression
func (av *AuthValidator) ValidateJSONPath(path string) error {
	if path == "" {
		return NewAuthError(ErrTypeConfigInvalid, "JSON path cannot be empty", "")
	}
	
	// Basic validation for JSON path format
	// This is a simplified validation - in a real implementation,
	// you might want to use a proper JSON path library for validation
	if !strings.Contains(path, ".") && !strings.Contains(path, "[") {
		// Simple field name is valid
		return nil
	}
	
	// Check for basic JSON path patterns
	validPathPattern := regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z_][a-zA-Z0-9_]*|\[\d+\])*$`)
	if !validPathPattern.MatchString(path) {
		return NewAuthError(ErrTypeConfigInvalid,
			fmt.Sprintf("invalid JSON path format: %s", path),
			"JSON path should follow the pattern: field.subfield or field[0].subfield")
	}
	
	return nil
}

// validateBearerToken validates a bearer token format
func (av *AuthValidator) validateBearerToken(token string) error {
	// Bearer tokens should be non-empty strings
	// In practice, you might want to validate specific formats like JWT
	if len(token) < 10 {
		return NewAuthError(ErrTypeTokenInvalid,
			"bearer token too short",
			"bearer tokens should be at least 10 characters long")
	}
	
	// Check for common bearer token patterns (basic validation)
	if strings.Contains(token, " ") {
		return NewAuthError(ErrTypeTokenInvalid,
			"bearer token should not contain spaces",
			"bearer tokens are typically single strings without spaces")
	}
	
	return nil
}

// validateAPIKeyToken validates an API key token format
func (av *AuthValidator) validateAPIKeyToken(token string) error {
	// API keys should be non-empty strings
	if len(token) < 8 {
		return NewAuthError(ErrTypeTokenInvalid,
			"API key too short",
			"API keys should be at least 8 characters long")
	}
	
	// Basic format validation for API keys
	validAPIKeyPattern := regexp.MustCompile(`^[a-zA-Z0-9_\-\.]+$`)
	if !validAPIKeyPattern.MatchString(token) {
		return NewAuthError(ErrTypeTokenInvalid,
			"invalid API key format",
			"API keys should contain only alphanumeric characters, underscores, hyphens, and dots")
	}
	
	return nil
}

// validateCustomToken validates a custom token format
func (av *AuthValidator) validateCustomToken(token string) error {
	// Custom tokens have minimal validation - just ensure they're not empty
	// The actual validation depends on the specific API requirements
	if len(token) == 0 {
		return NewAuthError(ErrTypeTokenInvalid,
			"custom token cannot be empty", "")
	}
	
	return nil
}

// ValidateAuthRequirements validates that required authentication types are available
func (av *AuthValidator) ValidateAuthRequirements(required []string, available map[string]*AuthState) error {
	if len(required) == 0 {
		return nil // No authentication required
	}
	
	missing := make([]string, 0)
	expired := make([]string, 0)
	
	for _, authType := range required {
		state, exists := available[authType]
		if !exists {
			missing = append(missing, authType)
		} else if state.IsExpired() {
			expired = append(expired, authType)
		}
	}
	
	if len(missing) > 0 {
		return NewAuthError(ErrTypeAuthRequired,
			fmt.Sprintf("missing required authentication types: %s", strings.Join(missing, ", ")),
			"ensure all required authentication flows are completed")
	}
	
	if len(expired) > 0 {
		return NewAuthError(ErrTypeTokenExpired,
			fmt.Sprintf("expired authentication types: %s", strings.Join(expired, ", ")),
			"re-authenticate for expired tokens")
	}
	
	return nil
}

// ValidateHeaderName validates a custom header name
func (av *AuthValidator) ValidateHeaderName(headerName string) error {
	if headerName == "" {
		return NewAuthError(ErrTypeConfigInvalid, "header name cannot be empty", "")
	}
	
	// HTTP header names should follow RFC 7230
	validHeaderPattern := regexp.MustCompile(`^[a-zA-Z][a-zA-Z0-9\-]*$`)
	if !validHeaderPattern.MatchString(headerName) {
		return NewAuthError(ErrTypeConfigInvalid,
			fmt.Sprintf("invalid header name: %s", headerName),
			"header names should start with a letter and contain only letters, numbers, and hyphens")
	}
	
	return nil
}

// ValidateQueryParam validates a query parameter name
func (av *AuthValidator) ValidateQueryParam(paramName string) error {
	if paramName == "" {
		return NewAuthError(ErrTypeConfigInvalid, "query parameter name cannot be empty", "")
	}
	
	// Query parameter names should be valid URL parameter names
	validParamPattern := regexp.MustCompile(`^[a-zA-Z][a-zA-Z0-9_]*$`)
	if !validParamPattern.MatchString(paramName) {
		return NewAuthError(ErrTypeConfigInvalid,
			fmt.Sprintf("invalid query parameter name: %s", paramName),
			"parameter names should start with a letter and contain only letters, numbers, and underscores")
	}
	
	return nil
}

// ValidateTokenPrefix validates a token prefix
func (av *AuthValidator) ValidateTokenPrefix(prefix string) error {
	// Token prefix can be empty (optional)
	if prefix == "" {
		return nil
	}
	
	// Basic validation - ensure it doesn't contain problematic characters
	if strings.Contains(prefix, "\n") || strings.Contains(prefix, "\r") {
		return NewAuthError(ErrTypeConfigInvalid,
			"token prefix cannot contain newline characters", "")
	}
	
	return nil
}

// Ensure AuthValidator implements the interface
var _ AuthValidatorInterface = (*AuthValidator)(nil)